#pragma once
#include <iostream>
#include <vector>
#include "mysocket.hpp"
#include "epoller.hpp"
#include "logmessage.hpp"
#include "nocopy.hpp"

using namespace std;

class EpollServer : public NoCopy
{
    static const int DEF_FD = -1;
    static const int INIT_SZ = 2;        //_pollfds的初始容量，可以设置为1024
    static const uint32_t NON_EVENT = 0; // 用于清空event

    Socket _listensock;
    uint16_t _port;
    string _ip;
    Epoller _epoller;

public:
    EpollServer(uint16_t port, const string ip = "0.0.0.0")
        : _port(port),
          _ip(ip)
    {
    }

    void Init()
    {
        _listensock.Bind(_ip, _port);
        _listensock.Listen();
        _epoller.EpollCtrl(EPOLL_CTL_ADD, _listensock.getsock(), EPOLLIN);
    }

    void Run()
    {
        epoll_event epevents[Epoller::SIZE];
        while (true)
        {
            int n = _epoller.EpollWait(epevents, Epoller::SIZE);
            if (n > 0)
            {
                Dispatcher(epevents, n);
            }
            cout << "----------------------------------" << endl;
        }
    }

    ~EpollServer()
    {
    }

private:
    void Dispatcher(const epoll_event *epevents, int sz)
    {
        for (int i = 0; i < sz; ++i)
        {
            uint32_t event = epevents[i].events;
            int sockfd = epevents[i].data.fd;
            if (event & EPOLLIN)
            {
                if(sockfd == _listensock.getsock())
                {
                    Acceptor();
                }
                else
                {
                    Receiver(sockfd);
                }
            }
            else if (event & EPOLLOUT)
            {
                //...
            }
            else
            {
                //...
            }
        }
    }

    void Acceptor()
    {
        string ip;
        uint16_t port;
        int svcfd = _listensock.Accept(&ip, &port);
        if (svcfd == -1)
            return;
        cout << "get a new link! " << ip << "/" << port << endl;
        _epoller.EpollCtrl(EPOLL_CTL_ADD, svcfd, EPOLLIN);
    }

    void Receiver(int fd)
    {
        char buffer[1024];
        int sz = recv(fd, &buffer, sizeof(buffer) - 1, 0);
        if (sz > 0)
        {
            buffer[sz] = 0;
            cout << "get a message from fd" << fd << endl
                 << "echo: " << buffer;
            string echo_str = "server echo $";
            echo_str += buffer;
            write(fd, echo_str.c_str(), echo_str.size() - 1);
        }
        else if (sz == 0)
        {
            _epoller.EpollCtrl(EPOLL_CTL_DEL, fd, 0); // 必须在close之前调用epoll_ctr
            close(fd);
            LogMessage(Debug, "client quit, service end. close fd%d", fd);
        }
        else
        {
            _epoller.EpollCtrl(EPOLL_CTL_DEL, fd, 0); // 必须在close之前调用epoll_ctr
            close(fd);
            LogMessage(Error, "recv error!");
        }
    }
};